package satir.cell;

import org.json.JSONArray;
import org.json.JSONException;

import satir.framework.JSONIOPerformer;
import satir.framework.JSONIOPerformer.JSONIOPerformerJSONDecodeException;
import satir.framework.JSONIOPerformer.JSONIOPerformerReadException;
import satir.framework.LazyInitiator;

/**
 * The Class Board.
 * @version 3.0 April 2012
 * @author Creative Family
 */
public class Board {

    /** The width(number of cell) of board. */
    private int width;
    /** The height(number of cell) of board. */
    private int height;
    /** Number of cell for walking. */
    private int numOfRoad;

    /** Storing the array of cell for walking. */
    private Cell[] cellRoadArray;
    /** The cell array for displaying cells in the board. */
    private Cell[][] cellArrayForDisplay;
    /** The head cell. */
    private ActionCell head;
    /** The tail cell. */
    private ActionCell tail;

    /**
     * Instantiates a new board. It will read the Board.config to retrieve
     * required information And create cell according to the configure file
     */
    public Board() {
	try {
	    // Use JSONIOPerformer to get the Board.config
	    JSONIOPerformer boardConfig = new JSONIOPerformer(
		    "config/Board.config");
	    // Retrieve the JSONObject and get required data
	    this.width = boardConfig.retrieve().getInt("Width");
	    this.height = boardConfig.retrieve().getInt("Height");
	    // Calculate the number of road
	    this.numOfRoad = 2 * (width + height) - 4;
	    cellArrayForDisplay = new Cell[width][height];
	    cellRoadArray = new Cell[numOfRoad];
	    JSONArray cellTypes = boardConfig.retrieve().getJSONArray(
		    "CellType");
	    // Create cell according to the boardCofig specified cell type
	    for (int i = 0; i < cellTypes.length(); i++) {
		ActionCell cell = (ActionCell) LazyInitiator.get(
			cellTypes.getString(i), cellTypes.getString(i), true);
		addToTail(cell);
		cellRoadArray[i] = cell;
	    }
	} catch (JSONIOPerformerReadException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	} catch (JSONIOPerformerJSONDecodeException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	} catch (JSONException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}

	// Put the created cell into array for display
	int leftSideCnt = numOfRoad - 1;
	int rightSideCnt = width;
	for (int i = 0; i < height; i++) {
	    for (int j = 0; j < width; j++) {
		if (i == 0) { // First row
		    cellArrayForDisplay[i][j] = cellRoadArray[j];
		} else if (i == height - 1) { // Last Row
		    cellArrayForDisplay[i][j] = cellRoadArray[leftSideCnt--];
		} else if (i < height) { // Middle Row
		    if (j == 0) { // Rightmost Column
			cellArrayForDisplay[i][j] = cellRoadArray[leftSideCnt--];
		    } else if (j == width - 1) { // Leftmost Column
			cellArrayForDisplay[i][j] = cellRoadArray[rightSideCnt++];
		    } else { // Center
			cellArrayForDisplay[i][j] = (Cell) LazyInitiator.get(
				"Cell", "Cell", false);
		    }
		}
	    }
	}
    }

    /**
     * Show board.
     */
    public void showBoard() {
	int rowNum = 0;
	int cellHeight = cellArrayForDisplay[0][0].getHeight();
	for (int i = 0; i < height; i++) {
	    for (int j = 0; j < cellHeight; j++) {
		for (int k = 0; k < width; k++) {
		    cellArrayForDisplay[i][k].display(rowNum);
		}
		rowNum++;
		System.out.println("");
	    }
	    rowNum = 0;
	    System.out.println("");
	}
    }

    /**
     * Adds cell the to head.
     * @param cell
     *            the cell that will be added to head
     */
    private void addToHead(final ActionCell cell) {
	if (head == null) {
	    tail = cell;
	    head = tail;
	} else {
	    cell.setNextCell(head);
	    head = cell;
	}
    }

    /**
     * Adds cell the to tail.
     * @param cell
     *            the cell that will be added to tail
     */
    private void addToTail(final ActionCell cell) {
	if (tail == null) {
	    tail = cell;
	    head = tail;
	} else {
	    tail.setNextCell(cell);
	    cell.setNextCell(head);
	    tail = cell;

	}
    }

    /**
     * Gets the head.
     * @return the head cell
     */
    public ActionCell getHead() {
	return this.head;
    }
}
